package sm.codec;

import java.util.Calendar;
import java.util.Date;

import org.apache.mina.core.buffer.IoBuffer;

import sm.codec.exception.DecodeException;
import sm.codec.exception.EncodeException;
import sm.def.Type;

public class TimeCodec extends NumberCodec {

	private int[] accumTable = new int[] { 0, 31, 59, 90, 120, 151, 181, 212,
			243, 273, 304, 334, 365 };

	private int[] laccumTable = new int[] { 0, 31, 60, 91, 121, 152, 182, 213,
			244, 274, 305, 335, 366 };

	private boolean isLeapYear(int year) {
		if ((year % 4) == 0) {
			if ((year % 100) == 0) {
				if ((year % 400) == 0)
					return true;
			} else {
				return true;
			}
		}
		return false;
	}

	@Override
	public Object decode(IoBuffer buffer) throws DecodeException {
		Object value = super.decode(buffer, Type.TIME_TYPE);
		if (value instanceof Double) {
			double timeVal = (Double) value;
			long minutes = (long) timeVal;
			double secondVar = timeVal - minutes;
			long seconds = 0;
			if (secondVar > 0) {
				seconds = Math.round(secondVar * 60);
			}
			int days = (int) (minutes / 1440);
			int minutesInDay = (int) (minutes % 1440);

			int year = (4 * days + 4) / (4 * 365 + 1);
			days -= year * 365 + (year - 1) / 4;

			boolean isLeapYear = isLeapYear(year);
			int[] yearTables = accumTable;
			if (isLeapYear) {
				yearTables = laccumTable;
			}

			int month = 0;
			while (yearTables[month] <= days) {
				month++;
			}
			--month;
			days -= yearTables[month];
			int dayOfMonth = days + 1;
			int hour = minutesInDay / 60;
			int minute = minutesInDay % 60;
			int second = (int) seconds;
			Calendar c = Calendar.getInstance();
			c.set(year, month, dayOfMonth, hour, minute, second);
			c.set(Calendar.MILLISECOND, 0);
			value = c.getTime();
		}

		return value;

	}

	@Override
	public void encode(IoBuffer buffer, Object value) throws EncodeException {
		if (value instanceof Date) {
			Date date = (Date) value;
			Calendar c = Calendar.getInstance();
			c.setTime(date);
			int year = c.get(Calendar.YEAR);
			int dayOfYear = c.get(Calendar.DAY_OF_YEAR) - 1;
			int hour = c.get(Calendar.HOUR);
			int minute = c.get(Calendar.MINUTE);
			int second = c.get(Calendar.SECOND);

			long minutes = year * 365l;
			minutes += (year - 1) / 4;
			minutes += dayOfYear;
			minutes *= 1440;
			minutes += hour * 60;
			minutes += minute;

			value = minutes + ((double) second / 60);
		}
		super.encode(buffer, value, Type.TIME_TYPE);
	}
}
